<?php
// +----------------------------------------------------------------------
// | Author: 张杨<zyzyzzy@vip.qq.com>
// +----------------------------------------------------------------------
// | 微信: zyzyzzy
// +----------------------------------------------------------------------
// | QQ：328662397
// +----------------------------------------------------------------------
// | Create_Date: 2020-10-18
// +----------------------------------------------------------------------
declare (strict_types = 1);

namespace app\Payment\controller;

use app\Payment\model\Domain;
use app\Payment\model\PaymentChannel;
use app\Payment\model\PaymentChannelClass;
use app\Payment\model\TradeData;
use app\Payment\model\TradeList;
use app\Payment\model\UserPaymentChannelClass;
use think\Db;
use think\Exception;
use think\facade\Config;
use think\Request;

class Payment
{
    public $parameter = "";
    public $payment_class_name = ""; //支付通道类名
    public $payment_obj = "";  //用来存储实例化的支付通道
    public $payment_channel_account = ""; //支付通道账号
    public $system_orderid = ""; //生成的系统订单号
    public function __construct(&$parameter)
    {
        $this->parameter = &$parameter;
    }

    public function index()
    {
        return (
            $this->verifyData()
            && $this->checkPaymentClass()
            && $this->instantiatePaymentObj()
            && $this->checkPaymentObj()
            && $this->getPaymentChannelAccount()
            && $this->createSystemOrderid()
            && $this->addTrade()
        );
    }

    //验证请求过来的数据是否合法
    private function verifyData()
    {
        if(!verify_sha1($this->parameter['formatdata'])){
            $this->parameter['msg'] = '请求数据不合法';
            return false;
        }
        return true;
    }

    //判断此用户是否可以调用所选通道分类
    private function checkPaymentClass()
    {
        //首先判断通道分类总开关是否半闭
        $PaymentChannelClassFind = PaymentChannelClass::where('classbm','=',$this->parameter['formatdata']['tongdao'])
                    ->field('id,status,classname')
                    ->findOrEmpty();
        if($PaymentChannelClassFind->isEmpty()){
            $this->parameter['msg'] = '通道分类不存在';
            return false;
        }
        if($PaymentChannelClassFind['status'] === 0){
            $this->parameter['msg'] = '通道分类['.$this->parameter['formatdata']['tongdao'].']已禁用';
            return false;
        }
        $this->parameter['payment_channel_class_id'] = $PaymentChannelClassFind['id'];
        //接下来判断给此用户是否设置了此通分类下的具体支付通道（我太难了，写注释太痛苦了!!!!!）
        $UserPaymentChannelClassFind = UserPaymentChannelClass::where([
            ['user_id','=',$this->parameter['formatdata']['usrid']],
            ['payment_channel_class_id','=',$PaymentChannelClassFind['id']]
        ])->field('payment_channel_id')->findOrEmpty();
        if($UserPaymentChannelClassFind->isEmpty() || $UserPaymentChannelClassFind['payment_channel_id'] === 0){
            $this->parameter['msg'] =  "用户在通道分类--".$PaymentChannelClassFind['classname']."--下无可用通道";
            return false;
        }
        $this->parameter['user_payment_channel_class_id'] = $UserPaymentChannelClassFind['id'];

        // 判断具体的支付通道
        $PaymentChannelFind = PaymentChannel::field('id,payment_codeing,payment_status')->findOrEmpty($UserPaymentChannelClassFind['payment_channel_id']);
        if($PaymentChannelFind->isEmpty()){
            $this->parameter['msg'] = '支付通道不存在';
            return false;
        }
        if($PaymentChannelFind['payment_status'] == 0){
            $this->parameter['msg'] = '支付通道已禁用';
            return false;
        }
        if (preg_match("/[^A-Za-z]/",$PaymentChannelFind['payment_codeing'])){
            $return_json['msg'] = '支付通道文件名格式错误';
            return false;
        }
        $this->parameter['payment_channel_id'] = $PaymentChannelFind['id'];
        $this->payment_class_name = $PaymentChannelFind['payment_codeing'];
        return true;
    }

    // 实例化通道类
    private function instantiatePaymentObj()
    {
        // $this->payment_class_name = 'PaymentDemo';
        $class_name =  "app\\Payment\\payment_channel\\".$this->payment_class_name;
        if(!class_exists($class_name)){
            $return_json['msg'] = '支付通道类文件格不存在';
            return false;
        }
        $this->payment_obj = new $class_name();
        return true;
    }

    //验证域名和状态
    private function checkPaymentObj()
    {
        //判断通道状态
        try {
            $check_status = ($this->payment_obj)->CheckStatus;
        }catch(Exception $exception){
            $check_status = true;
        }
        if(!$check_status){
            $this->parameter['msg'] = '支付通道类文件里已禁用';
            return false;
        }
        //验证域名
        try {
            $check_domain = ($this->payment_obj)->CheckDomain;
        }catch(Exception $exception){
            $check_domain = false;
        }
        if($check_domain){
            $user_domain = request()->host();
            $count = Domain::where([
                ['user_id','=',$this->parameter['formatdata']['userid']],
                ['domain','=',$user_domain]
            ])->count();
            if($count <= 0){
                $this->parameter['msg'] = '请求域名非法';
                return false;
            }

        }
        return true;
    }

    // 获取支付通道账号
    private function getPaymentChannelAccount()
    {
        // 实例化支付通道账号类
        $payment_account = new PaymentAccount($this->parameter);
        return $payment_account->index();
//        $this->payment_channel_account = [];
//        return true;
    }

    // 生成系统订单号
    private function createSystemOrderid()
    {
        // 获取指定系统订单号长度
        try {
            $orderid_leng = ($this->payment_obj)->Sysordernumberleng;
        }catch(Exception $exception){
            $orderid_leng = 32;
        }
        $orderid_leng<16?$orderid_leng=16:'';
        $orderid_one = date('YmdHis');
        if($orderid_leng >= 20){
            list($usec,$sec) = explode(" ",microtime());
            $orderid_two = substr(strval($usec),2,6) ;
            $exp = $orderid_leng - 20;
        }else{
            $orderid_two = "";
            $exp = $orderid_leng - 14;
        }
        $min = pow(10,$exp-1);
        $max = $min * 10 - 1;
        $orderid_three = rand($min,$max);
        $this->system_orderid = $orderid_one.$orderid_two.$orderid_three;
        //echo($this->system_orderid);
        return true;
    }

    // 写入数据库订单表
    private function addTrade()
    {
        //启动事务
        Db::startTrans();
        try {
            $trade_list = TradeList::create([
                'user_id' => $this->parameter['formatdata']['userid'],
                'system_orderid' => $this->system_orderid,
                'user_orderid' => $this->parameter['formatdata']['orderid'],
                'trade_status' => 0,
                // 是否测试订单
                'trade_type' => array_key_exists((Config::get('payment.test_field'))?(Config::get('payment.test_field')):md5(date('YmdHis')),$this->parameter['parameter'])?1:0,
                'trade_apply_datetime' => $this->parameter['formatdata']['orderdatetime'],
                'callbackurl' => $this->parameter['formatdata']['callbackurl'],
                'notifyurl' => $this->parameter['formatdata']['notifyurl'],
                'extend' => $this->parameter['formatdata']['extend']
            ]);
            if(!$trade_list){
                Db::rollback();
                $this->parameter['msg'] = '写入订单失败';
                return false;
            }

            $trade_data = TradeData::create([
                'trade_list_id' => $trade_list->id,
                'data_type' => 1,
                'data_content' => json_encode($this->parameter['parameter'])
            ]);
            if(!$trade_data){
                Db::rollback();
                $this->parameter['msg'] = '写入订单失败';
                return false;
            }

        }catch(Exception $exception){
             // 回滚事务
            Db::rollback();
            $this->parameter['msg'] = '系统错误';
            return false;
        }
        $trade = TradeList::create([
            'user_id' => $this->parameter['formatdata']['userid'],
            'system_orderid' => $this->system_orderid,
            'user_orderid' => $this->parameter['formatdata']['orderid']
        ]);
    }

}
